package com.adee.java.classloader;

import java.net.URL;

/**
 * Java中有两个classpath，一个是bootstrap classpath，另一个是classpath。
 *
 * classpath有如下两种形式：
 * 1.JAR files（JAR文件的全路径）;
 * 2.Paths to the top of package hierarchies.（顶级目录路径）
 *
 * 类加载的双亲委派模型中，bootstrap classloader 从 bootstrap classpath 路径加载类，
 * bootstrap classpath可通过JVM参数 -Xbootclasspath设置，通过System.getProperty("sun.boot.class.path")获取。
 *
 * 资源的访问方式
 * 资源(resource) 就是我们的程序需要访问的数据，例如图片、文本、视频、音频等等。
 *
 * 访问资源有两种方式：
 *
 * Location dependent
 * Location Independent
 *
 * 所谓Location Dependent，就是我们对资源的访问方式受程序所在位置的影响。
 *
 * 例如，在Java中，使用本机绝对路径访问文件时，就是一种Location Dependent的访问方法，代码如下：
 * File file = new File("/root/project/resource/config.xml")
 *
 * 如果项目中使用上述方式读取文件，当项目在其他目录或其他机器上部署和运行时，就需要修改上述代码中的文件路径，
 * 因此上述用法是LocationDependent的。
 *
 * Location Independent
 * 实现Location Independent的资源读取最常用的就是Class或ClassLoader类中的如下方法：
 *
 * URL getResource(String name)
 * InputStream getResourceAsStream(String name)
 * Enumeration<URL> getResources(String name)
 * getSystemResource, getSystemResources, getSystemResourceAsStream
 * 其中，前两个方法是Class和ClassLoader类都有的，后面的方法只有ClassLoader类有。
 *
 * 借助这些方法，可以实现从classpath下读取资源，或者相对于当前class文件所在的目录读取资源。
 *
 * 借助Class和ClassLoader都可以获取资源，并且后面分析源码可以看到，Class类获取资源的方法最终会
 * 调用ClassLoader类中对应的方法，那么，这两个类中获取资源的方法的区别在哪里呢？
 *
 * 区别在于ClassLoader类中的这两个方法仅支持相对于classpath的路径（开头不能加/，加了就获取不到classpath下的文件了），
 * 而Class类中的这两个方法除了支持相对于classpath的路径外（以/开头），还支持相对于当前class文件所在目录的路径（开头不加/）。
 *
 * ClassLoader.getSystemResource 等价于 ClassLoader.getSystemClassLoader().getResource，是用AppClassLoader加载资源，
 *
 */
public class GetResourceTest {
    public static void main(String[] args) {
        // 启动类加载器
        String bootstrap_classpath = System.getProperty("sun.boot.class.path"); // null
        System.out.println("用于启动类加载器的bootstrap classpath：" + bootstrap_classpath);

        // 用户指定类加载器（环境变量或命令行指定的classpath）
        String classpath = System.getProperty("java.class.path"); //
        System.out.println("手动指定的classpath：");
        for (String s : classpath.split(";")) {
            System.out.println(s);
        }

        // 扩展类加载器
        String ext_classpath = System.getProperty("java.ext.dirs"); // null
        System.out.println("ext classpath：" + ext_classpath);

        /**
         * F:\mycode\java\jdk\target\classes 是 classpath之一。尝试获取resources目录下config.xml文件的代码及其运行结果如下：
         */
        // 获取不到, 因为是相对于F:\mycode\java\jdk\target\classes\com\adee\java\classloader的路径
        URL resource1 = GetResourceTest.class.getResource("config.xml");
        // 下面3个能获取到, 因为是相对于classpath的路径
        URL resource2 = GetResourceTest.class.getResource("/config.xml");
        URL resource3 = GetResourceTest.class.getClassLoader().getResource("config.xml");
        URL resource4 = GetResourceTest.class.getClassLoader().getResource("./config.xml");
        // 获取不到，无法被解析为相对于classpath的路径
        URL resource5 = GetResourceTest.class.getClassLoader().getResource("/config.xml");
        URL resource6 = ClassLoader.getSystemResource("config.xml");

        System.out.println(resource1); // null
        System.out.println(resource2); // 非null  file:/F:/mycode/java/jdk/target/classes/config.xml
        System.out.println(resource3); // 非null  file:/F:/mycode/java/jdk/target/classes/config.xml
        System.out.println(resource4); // 非null  file:/F:/mycode/java/jdk/target/classes/config.xml
        System.out.println(resource5); // null
        System.out.println(resource6); // 非null  file:/F:/mycode/java/jdk/target/classes/config.xml



    }
}
